package cn.doitedu.eagle.queryservice;

import cn.doitedu.eagle.beans.BufferAvailLevel;
import cn.doitedu.eagle.beans.BufferResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;

/***
 * @author 涛哥
 * @nick_name "deep as the sea"
 * @contack qq:657270652 wx:doit_edu
 * @site www.51doit.cn
 * @date 2021/3/25
 * @desc BufferManager的redis查询实现类
**/
@Slf4j
public class RedisBufferManager implements BufferManager {

    private Jedis jedis;
    public RedisBufferManager(Jedis jedis) {
        this.jedis = jedis;
    }


    @Override
    public BufferResult getCountBuffer(String bufferKey, long queryStartTime, long queryEndTime, long querySplitPoint) {

        BufferResult bufferResult = new BufferResult();
        // 先设置为无效，后面有效的情况中更改，剩余情况则都是无效
        bufferResult.setAvailLevel(BufferAvailLevel.UN_AVAIL);
        bufferResult.setShiftEndTime(queryStartTime);
        bufferResult.setShiftEndTime(queryEndTime);

        try {
            // 缓存中key-value的格式： ( eventParamStr,cnt|endTime )
            String bufferValueStr = jedis.get("CNT|"+bufferKey);
            if (bufferValueStr == null || bufferValueStr.split("\\|").length < 3) return bufferResult;
            String[] split = bufferValueStr.split("\\|");
            long bufferStartTime = Long.parseLong(split[0]);
            long bufferEndTime = Long.parseLong(split[1]);
            int bufferValue = Integer.parseInt(split[2]);

            // 设置buffer的起始和结束时间，无论是否有效都不影响
            bufferResult.setBufferEndTime(bufferEndTime);
            bufferResult.setBufferStartTime(bufferStartTime);

            // buffer有效的情况：start必须对齐，end必须在查询范围之内，但要区分splitPoint
            if (bufferStartTime == queryStartTime && bufferEndTime <= queryEndTime) {
                if (bufferEndTime <= querySplitPoint) {
                    bufferResult.setAvailLevel(BufferAvailLevel.FAR_PARTIAL);
                } else {
                    bufferResult.setAvailLevel(BufferAvailLevel.FAR_NEAR_PARTIAL);
                }
                bufferResult.setBufferValue(bufferValue);
                // 只要有效，则将查询时间改为：buffer的end
                bufferResult.setShiftStartTime(bufferEndTime);
                // 其实这里是一句废代码，查询时间肯定是：条件中的end
                bufferResult.setShiftEndTime(queryEndTime);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 最后返回buffer查询结果
        return bufferResult;

    }

    @Override
    public BufferResult getSeqBuffer(String bufferKey, long queryStartTime, long queryEndTime, long querySplitPoint) {

        BufferResult bufferResult = new BufferResult();
        // 先设置为无效，后面有效的情况中更改，剩余情况则都是无效
        bufferResult.setAvailLevel(BufferAvailLevel.UN_AVAIL);
        bufferResult.setShiftEndTime(queryStartTime);
        bufferResult.setShiftEndTime(queryEndTime);

        // 缓存中key-value的格式： ( eventParamStr,cnt|endTime )
        try {
            long s = System.currentTimeMillis();
            String bufferValueStr = jedis.get("SEQ|"+bufferKey);
            long e = System.currentTimeMillis();
            log.info("获取一次序列缓存,缓存key: {} ,缓存value: {},耗时：{}",bufferKey,bufferValueStr,e-s);

            String[] split;
            if (StringUtils.isBlank(bufferValueStr) || (split=bufferValueStr.split("\\|")).length < 3) return bufferResult;

            long bufferStartTime = Long.parseLong(split[0]);
            long bufferEndTime = Long.parseLong(split[1]);
            int bufferValue = Integer.parseInt(split[2]);

            // 设置buffer的起始和结束时间，无论是否有效都不影响
            bufferResult.setBufferEndTime(bufferEndTime);
            bufferResult.setBufferStartTime(bufferStartTime);

            /*
             * seq查询情况下，buffer只有两种有效情况：
             * 1. buffer_start对齐start，且buffer_end>=分界点
             * |qs|______________|sp|_________|qe|
             * |bs|--------------------be|
             * 2. buffer_start对齐start，且buffer_start>=分界点，意味着查询范围完全落在near中
             * |sp|___|qs|_____________________|qe|
             *        |bs|_______________|be|
             * 这种情况下，buffer结果有效，且后续只要查询near，并且可以截短事件序列，意味着跨界查询
             * **/
            if (bufferStartTime == queryStartTime && bufferEndTime <= queryEndTime && (bufferEndTime >= querySplitPoint || bufferStartTime >= querySplitPoint)) {
                bufferResult.setShiftStartTime(bufferEndTime);
                bufferResult.setShiftEndTime(queryEndTime);

                bufferResult.setAvailLevel(BufferAvailLevel.FAR_NEAR_PARTIAL);
                bufferResult.setBufferValue(bufferValue);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return bufferResult;

    }

    @Override
    public void updateCountBuffer(String bufferKey, int bufferValue, long bufferStartTime, long bufferEndTime) throws Exception {
        jedis.set("CNT|"+bufferKey, bufferStartTime + "|" + bufferEndTime + "|" + bufferValue);
    }

    @Override
    public void updateSeqBuffer(String bufferKey, int bufferValue, long bufferStartTime, long bufferEndTime) throws Exception {
        log.info("更新序列缓存,缓存key: {} ,缓存value: {}",bufferKey,bufferStartTime + "|" + bufferEndTime + "|" + bufferValue);
        jedis.set("SEQ|"+bufferKey, bufferStartTime + "|" + bufferEndTime + "|" + bufferValue);
    }
}
